package com.eduagent.xwqeduagent.api.characterRecognition.PhotographySpeedCalculation;

import com.eduagent.xwqeduagent.api.characterRecognition.PhotographySpeedCalculation.util.SignUtil;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 拍照速算识别API
 * 调用讯飞拍照速算识别服务
 */
@Slf4j
public class PhotographySpeedCalculationAPI {

    // 拍照速算识别API接口地址
    private static final String API_URL = "https://rest-api.xfyun.cn/v2/itr";

    // 应用ID
    private final String appId;
    
    // 接口API Key
    private final String apiKey;
    
    // 接口API Secret
    private final String apiSecret;
    
    // OkHttp客户端
    private final OkHttpClient client;

    /**
     * 构造函数
     * @param appId 应用ID
     * @param apiKey 接口API Key
     * @param apiSecret 接口API Secret
     */
    public PhotographySpeedCalculationAPI(String appId, String apiKey, String apiSecret) {
        this.appId = appId;
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
        this.client = new OkHttpClient();
    }

    /**
     * 从文件路径识别速算题
     * @param filePath 图片文件路径
     * @return 识别结果JSON字符串
     * @throws IOException IO异常
     */
    public String recognizeFromFile(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IOException("文件不存在: " + filePath);
        }
        
        byte[] imageBytes = Files.readAllBytes(Paths.get(filePath));
        return recognizeFromByteArray(imageBytes);
    }

    /**
     * 从字节数组识别速算题
     * @param imageBytes 图片字节数组
     * @return 识别结果JSON字符串
     * @throws IOException IO异常
     */
    public String recognizeFromByteArray(byte[] imageBytes) throws IOException {
        // 将图片转为Base64
        String base64Image = Base64.getEncoder().encodeToString(imageBytes);
        return recognizeFromBase64(base64Image);
    }

    /**
     * 从Base64编码字符串识别速算题
     * @param base64Image Base64编码的图片
     * @return 识别结果JSON字符串
     * @throws IOException IO异常
     */
    public String recognizeFromBase64(String base64Image) throws IOException {
        // 构建请求体
        String bodyStr = buildRequestBody(base64Image);
        
        // 构建HTTP头
        Map<String, String> header = buildHeader(bodyStr);
        
        // 创建RequestBody
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(bodyStr, mediaType);
        
        // 构建请求
        Request request = new Request.Builder()
                .url(API_URL)
                .post(body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json,version=1.0")
                .addHeader("Host", header.get("Host"))
                .addHeader("Date", header.get("Date"))
                .addHeader("Digest", header.get("Digest"))
                .addHeader("Authorization", header.get("Authorization"))
                .build();
        
        // 发送请求并获取响应
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("请求失败，状态码: " + response.code() + ", 响应: " + response.body().string());
            }
            
            String responseBody = response.body().string();
            log.debug("拍照速算识别响应: {}", responseBody);
            return responseBody;
        }
    }
    
    /**
     * 构建请求体
     * @param base64Image Base64编码的图片
     * @return 请求体字符串
     */
    private String buildRequestBody(String base64Image) {
        JSONObject body = new JSONObject();
        
        // common字段
        JSONObject common = new JSONObject();
        common.put("app_id", appId);
        
        // business字段
        JSONObject business = new JSONObject();
        business.put("ent", "math-arith"); // 速算题类型
        business.put("aue", "raw"); // 预留压缩格式，目前仅支持raw
        
        // data字段
        JSONObject data = new JSONObject();
        data.put("image", base64Image);
        
        // 组装body
        body.put("common", common);
        body.put("business", business);
        body.put("data", data);
        
        return body.toJSONString();
    }
    
    /**
     * 构建HTTP请求头
     * @param bodyStr 请求体字符串
     * @return HTTP头部信息
     * @throws IOException IO异常
     */
    private Map<String, String> buildHeader(String bodyStr) throws IOException {
        Map<String, String> header = new HashMap<>();
        
        // 创建时间戳，格式为RFC1123
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        
        // 对body进行SHA-256签名，生成digest头部
        String digestBase64 = "SHA-256=" + SignUtil.signBody(bodyStr);
        
        // 构建签名原文
        StringBuilder builder = new StringBuilder("host: ").append("rest-api.xfyun.cn").append("\n")
                .append("date: ").append(date).append("\n")
                .append("POST ").append("/v2/itr").append(" HTTP/1.1").append("\n")
                .append("digest: ").append(digestBase64);
        
        // 使用HMAC-SHA256算法和apiSecret对签名原文进行签名
        String sha = SignUtil.hmacSign(builder.toString(), apiSecret);
        
        // 组装Authorization头
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", 
                apiKey, "hmac-sha256", "host date request-line digest", sha);
        
        // 填充header
        header.put("Host", "rest-api.xfyun.cn");
        header.put("Date", date);
        header.put("Digest", digestBase64);
        header.put("Authorization", authorization);
        
        return header;
    }
} 